package com.strong.sample.table.t_boxer_basic.service;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.*;
import cn.hutool.extra.pinyin.PinyinUtil;
import com.strong.sample.table.t_boxer_basic.TableBoxerBasicConstants;
import com.strong.sample.table.t_boxer_basic.enum_.BoxerEducationEnum;
import com.strong.sample.table.t_boxer_basic.enum_.BoxerGenderEnum;
import com.strong.sample.table.t_boxer_basic.enum_.BoxerNationalityEnum;
import com.strong.sample.table.t_boxer_basic.jpa.TableBoxerBasicDAO;
import com.strong.sample.table.t_boxer_basic.jpa.TableBoxerBasicDO;
import com.strong.sample.table.t_boxer_basic.jpa.TableBoxerBasicDO_;
import com.strong.sample.table.t_boxer_basic.model.TableBoxerBasicCreateDTO;
import com.strong.sample.table.t_boxer_basic.model.TableBoxerBasicRetrieveDTO;
import com.strong.sample.table.t_boxer_basic.model.TableBoxerBasicUpdateDTO;
import com.strong.sample.table.t_boxer_basic.model.TableBoxerBasicVO;
import com.strong.utils.JSON;
import com.strong.utils.StrongUtils;
import com.strong.utils.jpa.service.StrongServiceImpl;
import com.strong.utils.message.StrongMessageSource;
import jakarta.persistence.criteria.Predicate;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.domain.Page;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

import static com.strong.utils.jpa.JpaConstants.*;

/**
 * 运动员基本信息表 数据处理Service实现类
 *
 * @author Simen
 * @date 2022-02-07 20:11:23
 */
@Slf4j
@Service
@CacheConfig(cacheNames = {TableBoxerBasicConstants.TABLE_ENTITY})
public class TableBoxerBasicServiceImpl extends StrongServiceImpl<TableBoxerBasicDO, TableBoxerBasicVO> implements TableBoxerBasicService {

    /**
     * 注入的消息处理类
     */
    private final StrongMessageSource messageSource;

    /**
     * 注入的DAO类
     */
    private final TableBoxerBasicDAO tableBoxerBasicDAO;

    /**
     * 实例化
     *
     * @param messageSource      注入的消息处理类
     * @param tableBoxerBasicDAO 注入的DAO类
     */
    @Autowired
    public TableBoxerBasicServiceImpl(StrongMessageSource messageSource, TableBoxerBasicDAO tableBoxerBasicDAO) {
        this.messageSource = messageSource;
        this.tableBoxerBasicDAO = tableBoxerBasicDAO;
    }

    @Override
    @Cacheable(key = "#root.target + '_' + #root.methodName + '_' + #intId")
    public TableBoxerBasicDO getRecord(final Integer intId) {
        log.debug(intId.toString());
        Assert.notNull(intId, MSG_QUERY_ID_EMPTY);
        return tableBoxerBasicDAO.getReferenceById(intId);
    }

    @Override
    @CacheEvict(allEntries = true)
    public TableBoxerBasicDO getCreateAction(final TableBoxerBasicCreateDTO modelCreate) {
        log.debug(JSON.toJSONString(modelCreate));
        Assert.notNull(modelCreate, MSG_CONTENT_EMPTY);

        initTableBoxerBasicCreateDTO(modelCreate);

        TableBoxerBasicDO entity = BeanUtil.toBean(modelCreate, TableBoxerBasicDO.class, CopyOptions.create().setIgnoreNullValue(true));
        // 初始化实体类ID
        entity.setBoxerId(StrongUtils.getNoRepeatId(tableBoxerBasicDAO::getCountById));
        tableBoxerBasicDAO.save(entity);
        return entity;
    }

    @Override
    @Cacheable(keyGenerator = "vabKeyGenerator")
    public List<TableBoxerBasicDO> getAllList(final TableBoxerBasicRetrieveDTO modelRetrieve) {
        log.debug(JSON.toJSONString(modelRetrieve));
        Assert.notNull(modelRetrieve, MSG_SEARCH_CONDITION_EMPTY);

        // 以表达式生成一个查询条件对象
        Specification<TableBoxerBasicDO> specification = getSpecification(modelRetrieve);
        return tableBoxerBasicDAO.findAll(specification, modelRetrieve.getSort());
    }

    @Override
    @Cacheable(keyGenerator = "vabKeyGenerator")
    public Page<TableBoxerBasicDO> getPageList(final TableBoxerBasicRetrieveDTO modelRetrieve) {
        log.debug(JSON.toJSONString(modelRetrieve, true));
        Assert.notNull(modelRetrieve, MSG_SEARCH_CONDITION_EMPTY);

        // 以表达式生成一个查询条件对象
        Specification<TableBoxerBasicDO> specification = getSpecification(modelRetrieve);
        return tableBoxerBasicDAO.findAll(specification, modelRetrieve.getPageable());
    }

    @Override
    @CacheEvict(allEntries = true)
    public TableBoxerBasicDO getUpdateAction(final TableBoxerBasicUpdateDTO modelUpdate) {
        log.debug(JSON.toJSONString(modelUpdate));
        Assert.notNull(modelUpdate, MSG_CONTENT_EMPTY);

        // 通过id字段获取待修改的实体类（id字段不存在，需修改为对应字段）
        TableBoxerBasicDO entity = tableBoxerBasicDAO.getReferenceById(modelUpdate.getBoxerId());
        Assert.notNull(entity, MSG_RECORD_NONENTITY);
        BeanUtil.copyProperties(modelUpdate, entity, CopyOptions.create().setIgnoreNullValue(true));
        tableBoxerBasicDAO.save(entity);
        return entity;
    }

    @Override
    @Cacheable(key = "#root.target + '_' + #root.methodName + '_' + #intId")
    public TableBoxerBasicDO getUpdateRecord(final Integer intId) {
        log.debug(intId.toString());
        Assert.notNull(intId, MSG_QUERY_ID_EMPTY);
        return tableBoxerBasicDAO.getReferenceById(intId);
    }

    @Override
    @CacheEvict(allEntries = true)
    public Integer[] getDeleteAction(final Integer... intsId) {
        log.debug(ArrayUtil.toString(intsId));
        Assert.notEmpty(intsId, MSG_DELETE_RECORD_EMPTY);

        int[] intsTemp = new int[intsId.length];
        for (int i = 0; i < intsId.length; i++) {
            Assert.notNull(intsId[i], MSG_DELETE_RECORD_EMPTY);
            intsTemp[i] = intsId[i];
        }

        Integer intCount = tableBoxerBasicDAO.getCountByIdIn(intsTemp);
        Assert.isTrue(intCount == intsId.length, MSG_DELETE_RECORD_BEEN_NULL);

        tableBoxerBasicDAO.deleteAllByIdInBatch(Arrays.asList(intsId));
        return intsId;
    }

    // ===================内部=======================

    /**
     * 获取查询范式
     *
     * @return {@link Specification}<{@link TableBoxerBasicDO}>
     */
    protected Specification<TableBoxerBasicDO> getSpecification(final TableBoxerBasicRetrieveDTO modelRetrieve) {
        return (root, query, criteriaBuilder) -> {
            Map<String, String> mapSearch = modelRetrieve.getMapSearch();
            if (MapUtil.isNotEmpty(mapSearch)) {
                List<Predicate> listPredicate = new ArrayList<>();

                String strLike = MapUtil.getStr(mapSearch, TableBoxerBasicConstants.BOXER_NAME_ENTITY);
                if (StrUtil.isNotBlank(strLike)) {
                    listPredicate.add(criteriaBuilder.like(root.get(TableBoxerBasicDO_.boxerName), strLike));
                }

                return criteriaBuilder.and(ArrayUtil.toArray(listPredicate, Predicate.class));
            }
            return null;
        };
    }

    @Override
    @CacheEvict(value = TableBoxerBasicConstants.TABLE_ENTITY, allEntries = true)
    public void cacheEvict() {

    }

    // ===================扩展=======================

    public void initTableBoxerBasicCreateDTO(TableBoxerBasicCreateDTO model) {
        DateTime dateBirthday = IdcardUtil.getBirthDate(model.getBoxerIdNumber());

        model.setBoxerPhoneticInitials(PinyinUtil.getFirstLetter(model.getBoxerName(), ""));
        model.setBoxerPhoneticSurname(PinyinUtil.getPinyin(StrUtil.subPre(model.getBoxerName(), 1)));
        model.setBoxerBirthday(dateBirthday);

        // 设置民族，默认为未知
        BoxerNationalityEnum boxerNationalityEnum = EnumUtil.getBy(BoxerNationalityEnum.class, anEnum -> anEnum.getCode().equals(model.getBoxerNationality()));
        if (ObjUtil.isNull(boxerNationalityEnum)) {
            boxerNationalityEnum = BoxerNationalityEnum.N00;
        }
        model.setBoxerNationalityName(boxerNationalityEnum.getValue());

        if (IdcardUtil.getGenderByIdCard(model.getBoxerIdNumber()) == 1) {
            model.setBoxerGender(BoxerGenderEnum.MALE.getCode());
            model.setBoxerGenderName(BoxerGenderEnum.MALE.getValue());
        } else {
            model.setBoxerGender(BoxerGenderEnum.FEMALE.getCode());
            model.setBoxerGenderName(BoxerGenderEnum.FEMALE.getValue());
        }
    }
}